﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
using System.Collections;

using dHash;

namespace dHash_Server
{
    public partial class dHashForm : Form
    {
        server server;

        delegate void settext(string msg);

        public void updatestatus(string msg)
        {
            if (this.statusbox.InvokeRequired)
            {
                settext d = new settext(updatestatus);
                this.Invoke(d, new object[] { msg });
            }
            else
            {
                string temp = statusbox.Text;
                temp += msg + "\r\n";
                statusbox.Text = temp;
            }

            
        }

        public dHashForm()
        {
            InitializeComponent();

            hashFunc.DataSource = Enum.GetValues(typeof( hashfuncs)); 
            
            //hashFunc.DataSource = Enum.GetValues(typeof 

            try
            {
                BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
                provider.TypeFilterLevel = TypeFilterLevel.Full;

                IDictionary props = new Hashtable();
                props["port"] = 5566;

                updatestatus("Starting listening channel...");
                TcpChannel chan = new TcpChannel(props, null, provider);



                updatestatus("Registing channel...");
                ChannelServices.RegisterChannel(chan, true);

                updatestatus("Registing server as dHash...");
                RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(server),
                "dHash",
                WellKnownObjectMode.Singleton);

                //acquire my own stub not no need to call connect.
                server = (server)
                Activator.GetObject(typeof(server),
                "tcp://127.0.0.1:5566/dHash");
                
                //tasklist.Items.Add(new ListViewItem(new task("abc", "saltly", "abcedfgh", 6).taskrow()));


            }
            catch (Exception ex)
            {
            }
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            int max;

            if (!int.TryParse(txtMax.Text, out max))
            {
                errorProvider1.SetError(txtMax, "Invalid max char");
                return;
            }

            errorProvider1.SetError(txtMax, "");

            task newtask = new task(txtHash.Text, txtSalt.Text, txtChar.Text, max,(hashfuncs) hashFunc.SelectedValue);

            server.newtask(newtask);
            tasklist.Items.Add(new ListViewItem(newtask.taskrow()));

        }
    }

    [Serializable]
    public struct task
    {
        public string targethash, salt, charset;
        public int max, min;
        public hashfuncs func;

        public task(string _target,string _salt,string _charset, int _max,hashfuncs _func)
        {
            targethash = _target;
            salt = _salt;
            charset = _charset;
            max = _max;
            min = 1;
            func = _func;
        }
        public task(string _target, string _salt, string _charset, int _max, int _min,hashfuncs _func)
        {
            targethash = _target;
            salt = _salt;
            charset = _charset;
            max = _max;
            min = _min;
            func = _func;
        }

        public string[] taskrow()
        {
            string[] res = new string[6];
            res[0] = this.GetHashCode().ToString();
            res[1] = targethash;
            res[2] = salt;
            res[3] = charset;
            res[4] = max.ToString();
            res[5] = func.GetType().ToString();

            return res;
        }


    }

    public class server : MarshalByRefObject, dashServer
    {
        Dictionary<clientCallBack, List<jobdetails>> clients = new Dictionary<clientCallBack, List<jobdetails>>();
        List<task> tasks = new List<task>();
        List<jobdetails> jobs = new List<jobdetails>();
        task currentask;
        int jobid = 0;

        public void newtask(task task)
        {
            lock (tasks)
            {
                tasks.Add(task);
            }
        }

        void genprefix(string prefix, int len, task task)
        {
            if (len < 8)
            {
                genJobs(prefix, len, task);
            }
            else
            {
                len--;
                foreach (char c in task.charset)
                {
                    genprefix(prefix + c, len, task);
                }
            }
        }

        void genJobs(string prefix,int len,task task)
        {
            jobid ++;

            jobdetails newjob = new jobdetails();
            newjob.charset = task.charset;
            newjob.func = task.func;
            newjob.jobid = jobid;
            newjob.lentogo = len;
            newjob.prefix = prefix;
            newjob.salt = task.salt;
            newjob.targethash = task.targethash;
            newjob.taskhash = task.GetHashCode();

            while (jobs.Count > 100)
            {
                System.Threading.Thread.Sleep(500);
            }

            lock (jobs)
            {
                jobs.Add(newjob);
            }
            int min=1000000;
            clientCallBack c = clients.Keys.ElementAt(0);
            foreach (clientCallBack ccb in clients.Keys)
            {
                if (clients[ccb].Count < min)
                {
                    c = ccb;
                    min = clients[ccb].Count;
                }
                
            }

            clients[c].Add(newjob);
            c.addjob(newjob);
            
        }

        public void connect(clientCallBack ccb)
        {
            if (!clients.ContainsKey(ccb))
            {
                Program.form.updatestatus("Client connected... calling client");
                clients.Add(ccb, new List<jobdetails>());
                ccb.ping("hi :" + ccb.GetHashCode());
                Program.form.updatestatus("Client count :"+ clients.Count);
            }
            else
            {
                Program.form.updatestatus("Client already exists... silly error");
            }

        }

        public void found(int taskid, string password)
        {

        }

        public void failed(int taskid, int jobid)
        {
        }

    }
}
